/*
 * 础光实时操作系统PhotonRTOS -- 运行时序 测试框架
 *
 * Copyright (C) 2022, 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Lin Yang <s-yanglin@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#include "sequence_test.h"

VAR(uint8, AUTOMATIC) format_buf[1024];
VAR(uint8, AUTOMATIC) sequence_records[MAX_SEQUENCE];
VAR(uint32, AUTOMATIC) sequence_next = 0;
VAR(struct smp_lock, AUTOMATIC) lock;
VAR(uintptr_t, AUTOMATIC) flags;


/* 记录一个指定值到序列中,line为空则不输出任何内容 */
FUNC(void, OS_CODE) sequence_record_value(
	VAR(uint8, AUTOMATIC) value,
	P2VAR(const int8_t, AUTOMATIC, OS_APPL_DATA) line, ...)
{
	VAR(uint32, AUTOMATIC) len;
	va_list args;

	smp_lock_irqsave(&lock, flags);

	va_start(args, line);
	if (sequence_next >= MAX_SEQUENCE) {
		panic("时序记录超出最大值\n");
	}

	sequence_records[sequence_next] = value;
	if (line[0] != '\0') {
		len = vsprintf(format_buf, line, args);
		format_buf[len] = '\0';
		printk("%5d :\t (%d):\t%s\n", sequence_next, value, format_buf);
	}
	sequence_next++;
	va_end(args);

	smp_unlock_irqrestore(&lock, flags);
}

/* 记录任务号到序列中,line为空则不输出任何内容 */
FUNC(void, OS_CODE) sequence_record(
	P2VAR(const int8_t, AUTOMATIC, OS_APPL_DATA) line, ...)
{
	VAR(TaskType, AUTOMATIC) task_id;
	VAR(uint32, AUTOMATIC) len;
	va_list args;

	smp_lock_irqsave(&lock, flags);

	va_start(args, line);
	if (sequence_next >= MAX_SEQUENCE) {
		panic("时序记录超出最大值\n");
	}

	GetTaskID(&task_id);
	sequence_records[sequence_next] = task_id;
	if (line[0] != '\0') {
		len = vsprintf(format_buf, line, args);
		format_buf[len] = '\0';
		printk("%5d :\ttask %d:\t%s\n", sequence_next, task_id, format_buf);
	}
	sequence_next++;
	va_end(args);

	smp_unlock_irqrestore(&lock, flags);
}

/**
 * 验证记录的序列与输入序列是否一致,并清空序列
 * 一致返回 0, 不一致返回 1
 */
FUNC(uint8, OS_CODE) assert_sequence_records(
	P2VAR(uint8, AUTOMATIC, OS_APPL_CONST) right_sequ)
{
	VAR(uint32, AUTOMATIC) i = 0;
	VAR(uint8, AUTOMATIC) ret = 0;

	sequence_record_value(SEQUENCE_END, "");

	smp_lock_irqsave(&lock, flags);

	for (i = 0; i < sequence_next; i++) {
		if (right_sequ[i] != sequence_records[i]) {
			if (sequence_records[i] != SEQUENCE_END) {
				pr_warn("sequence wrong at %d, it should be %d instead of %d\n",
					i, right_sequ[i], sequence_records[i]);
			} else {
				pr_warn("sequence wrong at %d, it should be %d instead of none\n",
					i, right_sequ[i]);
			}
			ret = 1;
			goto out;
		}
	}
out:
	sequence_next = 0;
	smp_unlock_irqrestore(&lock, flags);
	return ret;
}

